#pragma once
#include <iostream>
#include <memory>
#include <functional>
#include <string>
#include <thread>
#include <pthread.h>
#include "sock.hpp"

static const uint16_t default_port = 8888;
using func_t = std::function<std::string(std::string &)>;
class http_server;

class thread_data
{
public:
    thread_data(std::string &ip, uint16_t port, int sock, http_server *phs)
    :_client_ip(ip)
    ,_client_port(port)
    ,_client_sock(sock)
    ,_phs(phs)
    {}
   
    std::string _client_ip;
    uint16_t _client_port;
    int _client_sock;
    http_server *_phs;
};

class http_server
{
public:
    http_server(func_t cb, uint16_t port = default_port)
    :_port(port)
    ,_cb(cb)
    {}
    ~http_server(){}

    void init()
    {
        _listen_sock.Socket();
        _listen_sock.Bind(_port);
        _listen_sock.Listen();
    }

    void request(int sock)
    {
        char buffer[4096];
        std::string req;
        // 认为一次读完，不做检查
        int ret = recv(sock, buffer, sizeof(buffer) - 1, 0);//?
        if(ret != -1)
        {
            buffer[ret] = 0;
            req = buffer;
            std::string response = _cb(req);
            send(sock, response.c_str(), response.size(), 0);
        }
        else
        {
            std::cout << "客户端退出" << std::endl;
        }
    }

    static void* thread_routine(void *args)
    {
        // 线程分离
        pthread_detach(pthread_self());
        thread_data *ptd = static_cast<thread_data*>(args);
        ptd->_phs->request(ptd->_client_sock);
        close(ptd->_client_sock);
        delete ptd;
        return nullptr;
    }

    void start()
    {
        while(1)
        {
            std::string client_ip;
            uint16_t client_port;
            int client_sock = _listen_sock.Accept(&client_ip, &client_port);
            if(client_sock == -1) continue;

            std::cout << "客户端[" << client_ip << ":" << client_port << "]连接成功！" << std::endl;

            pthread_t tid;
            thread_data *ptd = new thread_data(client_ip, client_port, client_sock, this);
            pthread_create(&tid, nullptr, thread_routine, ptd);
        }
    }
private:
    uint16_t _port;
    func_t _cb;
    sock _listen_sock;
};